/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/

#include "../SDL_cellvideo.h"

#ifndef CELL_NO_SOFT_INPUT

#define BUILDING_CELLPADMAP
#include "SDL_celloskimage.h"
#include "SDL_cellbuttons.h"
#undef BUILDING_CELLPADMAP

/* Data */
#include "../../default_cursor.h"

/** Helpers **/
static void						LoadImages							()
{
	if(!CELL_Video.OSK.Cursor)
	{
		uint32_t* oskImage = malloc(sizeof(CELL_OSK_Image) * 4);
		for(int i = 0; i != OSK_HEIGHT; i ++)
		{
			for(int j = 0; j != OSK_WIDTH; j += 2)
			{
				uint8_t byte = CELL_OSK_Image[(i * OSK_WIDTH / 2) + (j / 2)];
				uint8_t first = byte & 0xF0;
				uint8_t second = (byte & 0xF) << 4;


				oskImage[i * OSK_WIDTH + j + 0] = 0xFF000000 | (first << 16) | (first << 8) | first;
				oskImage[i * OSK_WIDTH + j + 1] = 0xFF000000 | (second << 16) | (second << 8) | second;
			}
		}
		CELL_IMAGE_Load(&CELL_Video.OSK.Image, 0, OSK_HEIGHT * 2, OSK_WIDTH, OSK_HEIGHT, (void*)oskImage, OSK_WIDTH, OSK_HEIGHT);
		free(oskImage);

		CELL_Video.OSK.Cursor = CELL_CURSOR_Create(0, default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);

		for(int i = 0; i != NUM_BUTTONS; i ++)
		{
			CELL_IMAGE_Load(&CELL_Video.Pads.ButtonMap[i].Image, 0, 0, 50, 50, (void*)CELL_ButtonImages[i], 30, 30);
		}
	}
}

static int						PointInRect							(const SDL_Rect* aRect, int32_t aX, int32_t aY)
{
	return (aX >= aRect->x && aY >= aRect->y && aX < aRect->x + aRect->w && aY < aRect->y + aRect->h);
}

static void						DrawButtonMaps						()
{
	for(int i = 0; i != NUM_BUTTONS; i ++)
	{
		/* If the button is mapped and not nullified */
		if(CELL_Video.Pads.ButtonMap[i].Mapped && !CELL_Video.Pads.ButtonMap[i].Nullify)
		{
			CELL_IMAGE_Draw_TA(&CELL_Video.Pads.ButtonMap[i].Image, CELL_Video.Pads.ButtonMap[i].Mapped->ImageArea.x, OSK_HEIGHT * 2 + CELL_Video.Pads.ButtonMap[i].Mapped->ImageArea.y, .5f);
		}
	}
}

static void						UpdateMaps							(uint32_t aNewButtons, uint32_t aOldButtons)
{
	if(aOldButtons != aNewButtons && CELL_Video.OSK.Selected)
	{
		for(int i = 0; i != NUM_BUTTONS; i ++)
		{
			/* If the button is not nullified, and this button is freshly pressed */
			if((!CELL_Video.Pads.ButtonMap[i].Nullify) && (aNewButtons & (1 << i)) && !(aOldButtons & (1 << i)))
			{
				CELL_PAD_KEYBOARD_Map(i, CELL_Video.OSK.Selected->HIDID);
			}
		}
	}
}

/* Button Mapping */
/* Return the HID_ID that the specified button is mapped to */
enum HID_ID						CELL_PAD_KEYBOARD_GetMap			(uint32_t aButton)
{
	if(aButton < NUM_BUTTONS && CELL_Video.Pads.ButtonMap[aButton].RealMapped)
	{
		return CELL_Video.Pads.ButtonMap[aButton].RealMapped->HIDID;
	}

	return HID_NOEVENT;
}

/* Map the specified button to the HID_ID, but only if it is found on the keyboard */
void							CELL_PAD_KEYBOARD_Map				(uint32_t aButton, enum HID_ID aID)
{
	if(!aButton < NUM_BUTTONS && aID != HID_NOEVENT)
	{
		for(int i = 0; i != OSK_KEY_MAP_SIZE; i ++)
		{
			if(CELL_OSK_Map[i].HIDID == aID)
			{
				if(!CELL_Video.OSK.MappingOverride)
				{
					CELL_Video.Pads.ButtonMap[aButton].Mapped = &CELL_OSK_Map[i];
				}

				CELL_Video.Pads.ButtonMap[aButton].RealMapped = &CELL_OSK_Map[i];
				return;
			}
		}
	}
	else if(aButton < NUM_BUTTONS && aID == HID_NOEVENT)
	{
		if(!CELL_Video.OSK.MappingOverride)
		{
			CELL_Video.Pads.ButtonMap[aButton].Mapped = 0;
		}

		CELL_Video.Pads.ButtonMap[aButton].RealMapped = 0;
		return;
	}
}

/* Enter keyboard mode */
void							CELL_PAD_KEYBOARD_Enter				(enum PadMode aOldMode)
{
	LoadImages();
	SDL_ResetKeyboard();
	CELL_ReleaseAllMouseButtons();
}

/* Exit keyboard mode, and release all buttons */
void							CELL_PAD_KEYBOARD_Exit				(enum PadMode aNewMode)
{
	SDL_ResetKeyboard();
	CELL_ReleaseAllMouseButtons();
}

/* Code */
void							CELL_PAD_KEYBOARD_Draw				()
{
	/* Setup projection */
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrthof(0, OSK_WIDTH, OSK_HEIGHT * 3, 0, -1, 1);

	/* Draw the keyboard */
	CELL_IMAGE_Draw_TA(&CELL_Video.OSK.Image, 0, 0, .75f);

	/* Draw selections */
	GLfloat vtx[20];
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &vtx[0]);
	glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &vtx[3]);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_TEXTURE_2D);

	if(SDL_GetModState())
	{
		glColor4f(0.25f, 0.0f, 0.0f, 0.25f);

		for(int i = 0; i != OSK_MOD_MAP_SIZE; i ++)
		{
			if(SDL_GetModState() & CELL_OSK_ModifierIndex[i])
			{
				CELL_PSGL_SetRectangle(vtx, CELL_OSK_ModifierMap[i].ImageArea.x, OSK_HEIGHT * 2 + CELL_OSK_ModifierMap[i].ImageArea.y, CELL_OSK_ModifierMap[i].ImageArea.w, CELL_OSK_ModifierMap[i].ImageArea.h);					
				glDrawArrays(GL_QUADS, 0, 4);
			}
		}
	}

	if(CELL_Video.OSK.Selected)
	{
		glColor4f(0.0f, 0.0f, 0.25f, 0.25f);

		CELL_PSGL_SetRectangle(vtx, CELL_Video.OSK.Selected->ImageArea.x, OSK_HEIGHT * 2 + CELL_Video.OSK.Selected->ImageArea.y, CELL_Video.OSK.Selected->ImageArea.w, CELL_Video.OSK.Selected->ImageArea.h);
		glDrawArrays(GL_QUADS, 0, 4);
	}

	if(!CELL_Video.OSK.MappingOverride && CELL_Video.OSK.MappingMode)
	{
		glColor4f(0.0f, 0.75f, 0.0f, 0.50f);		

		CELL_PSGL_SetRectangle(vtx, CELL_Video.OSK.MappingMode->ImageArea.x, OSK_HEIGHT * 2 + CELL_Video.OSK.MappingMode->ImageArea.y, CELL_Video.OSK.MappingMode->ImageArea.w, CELL_Video.OSK.MappingMode->ImageArea.h);
		glDrawArrays(GL_QUADS, 0, 4);
	}

	if(CELL_Video.OSK.Down)
	{
		glColor4f(0.75f, 0.0f, 0.0f, 0.50f);

		CELL_PSGL_SetRectangle(vtx, CELL_Video.OSK.Down->ImageArea.x, OSK_HEIGHT * 2 + CELL_Video.OSK.Down->ImageArea.y, CELL_Video.OSK.Down->ImageArea.w, CELL_Video.OSK.Down->ImageArea.h);
		glDrawArrays(GL_QUADS, 0, 4);
	}

	glColor4f(1, 1, 1, 1);
	glDisable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);


	/* Draw the button maps */
	DrawButtonMaps();

	/* Draw the cursor */
	CELL_CURSOR_Draw(CELL_Video.OSK.Cursor, CELL_Video.OSK.CursorX, OSK_HEIGHT * 2 + CELL_Video.OSK.CursorY, 4);

	/* Reset projection */
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
}

void FASTCALL 					CELL_PAD_KEYBOARD_Buttons			(uint32_t aNewButtons, uint32_t aOldButtons)
{
	if(!CELL_Video.OSK.MappingOverride && CELL_Video.OSK.MappingMode)
	{
		if((aNewButtons & 0x4000) && !(aOldButtons & 0x4000) && PointInRect(&CELL_Video.OSK.MappingMode->ImageArea, CELL_Video.OSK.CursorX, CELL_Video.OSK.CursorY))
		{
			CELL_Video.OSK.MappingMode = 0;
		}
		else
		{
			UpdateMaps(aNewButtons, aOldButtons);
		}

		return;
	}

	/* Process Mapped keys */
	for(int i = 0; i != NUM_BUTTONS; i ++)
	{
		/* If this button is not nullified, and this button is mapped as a keyboard action, but NOT a mouse action, and this button is not cross */
		if((CELL_Video.Pads.ButtonMap[i].Nullify == 0) && CELL_Video.Pads.ButtonMap[i].Mapped && CELL_Video.Pads.ButtonMap[i].Mapped->MouseButton == 0 && i != 14)
		{
			CELL_PAD_ProcessButton(i, aNewButtons & (1 << i), aOldButtons & (1 << i));
		}
	}

	/* If cross was just pressed and a key is highlighted */
	if((aNewButtons & 0x4000) && (!(aOldButtons & 0x4000)) && CELL_Video.OSK.Selected)
	{
		/* Press normal button */
		if(CELL_Video.OSK.Selected->HIDID)
		{
			CELL_Video.OSK.Down = CELL_Video.OSK.Selected;
			CELL_DoKeyEventSDLK(CELL_Video.OSK.Selected->HIDID, SDL_PRESSED, (SDL_GetModState() & KMOD_SHIFT) ? CELL_Video.OSK.Selected->ShiftCharacter : CELL_Video.OSK.Selected->Character);
		}
		/* Press modifier */
		else if(CELL_Video.OSK.Selected->ModifierID != KMOD_NONE)
		{
			/* The SDL modifier IDs aren't sequential, so here we search the CELL_OSK_ModifierMap for info about our key */
			for(int i = 0; i != OSK_MOD_MAP_SIZE; i ++)
			{
				if(CELL_OSK_ModifierMap[i].ModifierID == CELL_Video.OSK.Selected->ModifierID)
				{
					CELL_DoModifierEvent(CELL_OSK_ModifierMap[i].Symbol, (SDL_GetModState() & CELL_Video.OSK.Selected->ModifierID) ? SDL_RELEASED : SDL_PRESSED);
				}
			}
		}
		/* Else an action */
		else if(CELL_Video.OSK.Selected->Flags)
		{
			if(!CELL_Video.OSK.MappingOverride && CELL_Video.OSK.Selected->Flags == 3) /* Mapping mode */
			{
				CELL_Video.OSK.MappingMode = CELL_Video.OSK.Selected;

				if(CELL_Video.OSK.Down)
				{
					CELL_DoKeyEventSDLK(CELL_Video.OSK.Down->HIDID, SDL_RELEASED, 0);
					CELL_Video.OSK.Down = 0;
				}

				SDL_ResetKeyboard();
			}
		}
	}
	/* We just released cross, send any keyups */
	else if((!(aNewButtons & 0x4000)) && (aOldButtons & 0x4000) && CELL_Video.OSK.Down)
	{
		CELL_DoKeyEventSDLK(CELL_Video.OSK.Down->HIDID, SDL_RELEASED, 0);
		CELL_Video.OSK.Down = 0;
	}
}

void FASTCALL 					CELL_PAD_KEYBOARD_Axes				(int32_t aXAxis, int32_t aYAxis)
{
	int xaxis = (aXAxis - 0x80) / 8;
	int yaxis = (aYAxis - 0x80) / 8;

	if(xaxis || yaxis)
	{
		/* Move it */
		CELL_Video.OSK.CursorX += xaxis;
		CELL_Video.OSK.CursorY += yaxis;

		/* Clamp it */
		CELL_Video.OSK.CursorX = (CELL_Video.OSK.CursorX < 0) ? 0 : CELL_Video.OSK.CursorX;
		CELL_Video.OSK.CursorY = (CELL_Video.OSK.CursorY < 0) ? 0 : CELL_Video.OSK.CursorY;
		CELL_Video.OSK.CursorX = (CELL_Video.OSK.CursorX >= OSK_WIDTH) ? OSK_WIDTH - 1 : CELL_Video.OSK.CursorX;
		CELL_Video.OSK.CursorY = (CELL_Video.OSK.CursorY >= OSK_HEIGHT) ? OSK_HEIGHT - 1 : CELL_Video.OSK.CursorY;

		/* Serach the osk map for a selected key */
		CELL_Video.OSK.Selected = 0;
		for(int i = 0; i != OSK_KEY_MAP_SIZE; i ++)
		{
			if(PointInRect(&CELL_OSK_Map[i].ImageArea, CELL_Video.OSK.CursorX, CELL_Video.OSK.CursorY))
			{
				CELL_Video.OSK.Selected = &CELL_OSK_Map[i];
				break;
			}
		}
	}
}

#endif
